﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using Nop.Core;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Shipping;
using Nop.Core.Plugins;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Configuration;
using Nop.Services.Directory;
using Nop.Services.Localization;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Tax;
using PayCenter.Sdk.Models;
using PayCenter.Sdk.Requests;
using Nop.Services.Logging;
using static Nop.Core.Domain.Catalog.WalletTemplate;
using Newtonsoft.Json.Linq;
using Nop.Core.Domain.Catalog;
using Autofac;
using Nop.Core.Infrastructure;
using Nop.Core.Configuration;
using Nop.Web.Services;
using Nop.Web.Services.Utils;

namespace Nop.Plugin.Payments.HPay
{
    public class HPayPaymentProcessor : BasePlugin, IPaymentMethod
    {
        const string ORDER_CUSTOMER_KEY = "OrderPayInfo";

        #region Fields

        private readonly CurrencySettings _currencySettings;
        private readonly ICheckoutAttributeParser _checkoutAttributeParser;
        private readonly ICurrencyService _currencyService;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ILocalizationService _localizationService;
        private readonly IPaymentService _paymentService;
        private readonly ISettingService _settingService;
        private readonly ITaxService _taxService;
        private readonly IWebHelper _webHelper;
        private readonly IWorkContext _workContext;
        private readonly IProductService _productService;
        private readonly IPriceCalculationService _priceCalculationService;
        private readonly ILogger _logger;
        private readonly IOrderService _orderService;
        private readonly IOrderProcessingService _orderProcessingService;
        private readonly NopConfig _config;
        private readonly HPaySdkHelper _paySdkHelper;
        private readonly HUCSdkHelper _hUCSdkHelper;
        #endregion

        #region Ctor

        public HPayPaymentProcessor(CurrencySettings currencySettings,
            HPaySdkHelper paySdkHelper,
            HUCSdkHelper hUCSdkHelper,
            ICheckoutAttributeParser checkoutAttributeParser,
            ICurrencyService currencyService,
            IGenericAttributeService genericAttributeService,
            IHttpContextAccessor httpContextAccessor,
            ILocalizationService localizationService,
            IPaymentService paymentService,
            ISettingService settingService,
            ITaxService taxService,
            IWebHelper webHelper, IWorkContext workContext, IProductService productService,
            IPriceCalculationService priceCalculationService, ILogger logger, IOrderService orderService, IOrderProcessingService orderProcessingService, NopConfig config)
        {

            this._currencySettings = currencySettings;
            this._checkoutAttributeParser = checkoutAttributeParser;
            this._currencyService = currencyService;
            this._genericAttributeService = genericAttributeService;
            this._httpContextAccessor = httpContextAccessor;
            this._localizationService = localizationService;
            this._paymentService = paymentService;
            this._settingService = settingService;
            this._taxService = taxService;
            this._webHelper = webHelper;
            this._workContext = workContext;
            this._productService = productService;
            this._priceCalculationService = priceCalculationService;
            this._logger = logger;
            this._orderService = orderService;
            this._orderProcessingService = orderProcessingService;
            this._config = config;
            _paySdkHelper = paySdkHelper;
            _hUCSdkHelper = hUCSdkHelper;



        }
        #endregion

        public bool SupportCapture => false;

        public bool SupportPartiallyRefund => false;

        public bool SupportRefund => false;

        public bool SupportVoid => false;

        public RecurringPaymentType RecurringPaymentType => RecurringPaymentType.NotSupported;

        public PaymentMethodType PaymentMethodType => PaymentMethodType.Standard;

        public bool SkipPaymentInfo => false;

        public string PaymentMethodDescription => "华商情聚合支付渠道";

        /// <summary>
        /// 取消定期支付
        /// </summary>
        /// <param name="cancelPaymentRequest"></param>
        /// <returns></returns>
        public CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest)
        {
            return new CancelRecurringPaymentResult { Errors = new[] { "定期支付未启用" } };
        }

        /// <summary>
        /// 是否能从新付款 PaymentMethodType.Redirection 时有效
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        public bool CanRePostProcessPayment(Order order)
        {
            if (order == null)
                throw new ArgumentNullException(nameof(order));

            //it's not a redirection payment method. So we always return false
            return false;
        }

        /// <summary>
        /// 交易快照
        /// </summary>
        /// <param name="capturePaymentRequest"></param>
        /// <returns></returns>
        public CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest)
        {
            return new CapturePaymentResult { Errors = new[] { "Capture method not supported" } };
        }

        /// <summary>
        /// 附加手续费
        /// </summary>
        /// <param name="cart"></param>
        /// <returns></returns>
        public decimal GetAdditionalHandlingFee(IList<ShoppingCartItem> cart)
        {
            return _paymentService.CalculateAdditionalFee(cart, 0, false);
        }

        /// <summary>
        /// 获取支付信息
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        public ProcessPaymentRequest GetPaymentInfo(IFormCollection form)
        {
            var result = new ProcessPaymentRequest
            {
                OrderGuid = Guid.NewGuid()
            };
            if (form.TryGetValue("cartIds", out StringValues cartValues))
            {
                if (cartValues.Count > 0)
                {
                    var cartIdList = form["cartIds"].First().Split(",").Select(s => int.Parse(s)).ToList();

                    if (cartIdList.Count() < 1)
                    {
                        throw new Exception("购物车为空");
                    }

                    result.CustomValues.Add(ORDER_CUSTOMER_KEY, new OrderPayInfo()
                    {
                        OrderId = result.OrderGuid,
                        CartItemIds = cartIdList
                    });
                    return result;
                }
                else
                {
                    throw new Exception("购物车为空");
                }
            }
            else
            {
                throw new Exception("购物车为空");
            }



        }

        /// <summary>
        /// 显示在前台的ViewComponent的名称
        /// </summary>
        /// <returns></returns>
        public string GetPublicViewComponentName()
        {
            return "HPayViewComponent";
        }

        /// <summary>
        /// 返回是否隐藏当前支付方式(商品是否支持此方式支付)
        /// </summary>
        /// <param name="cart"></param>
        /// <returns></returns>
        public bool HidePaymentMethod(IList<ShoppingCartItem> cart)
        {
            return false;
        }

        /// <summary>
        /// 预处理支付信息
        /// </summary>
        /// <param name="postProcessPaymentRequest"></param>
        public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest)
        {

        }

        public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
        {
            ProcessPaymentResult result = new ProcessPaymentResult();

            if (!processPaymentRequest.CustomValues.TryGetValue(ORDER_CUSTOMER_KEY, out object orderPayInfoObj))
            {
                result.AddError("订单支付信息未发现");
            }
            else
            {
                OrderPayInfo orderPayInfo = null;
                if (orderPayInfoObj is OrderPayInfo)
                {
                    orderPayInfo = orderPayInfoObj as OrderPayInfo;
                }
                if (orderPayInfoObj is JObject)
                {
                    try
                    {
                        orderPayInfo = (orderPayInfoObj as JObject).ToObject<OrderPayInfo>();
                    }
                    catch (Exception ex)
                    {
                        _logger.Error("OrderPayInfo 类型转换错误", ex);
                    }

                }
                if (orderPayInfo != null)
                {

                    if (orderPayInfo.OrderId.Equals(processPaymentRequest.OrderGuid))
                    {

                        /**
                         * 
                         *  TODO  目前不允许一次支付使用多个钱包,因为还涉及到相关计算和设置,包括运费,优惠扣减
                         * 
                         */
                        var cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(s => orderPayInfo.CartItemIds.Contains(s.Id));
                        if (cart.Count() != orderPayInfo.CartItemIds.Count)
                        {
                            result.AddError("购物车商品数目不匹配");
                        }
                        else
                        {
                            var cartWithWallets = cart.Select(s => new { CartItem = s, Wallets = _productService.GetWallet(s.ProductId) });
                            if (cartWithWallets.Where(s => s.Wallets.Count > 1).Any())
                            {
                                result.AddError("暂不支持多钱包种类支付(产品包含多个钱包)");
                            }
                            else
                            {
                                var wallets = cartWithWallets.SelectMany(s => s.Wallets).Select(s => s.WalletId).GroupBy(s => s);
                                if (wallets.Count() < 1)
                                {
                                    result.AddError("产品未包含钱包");
                                }
                                else if (wallets.Count() > 1)
                                {
                                    result.AddError("暂不支持多钱包种类支付(购物车包含多个钱包)");
                                }
                                else
                                {

                                    var ucMemberId = _hUCSdkHelper.GetMemberId(_workContext.CurrentCustomer);
                                    if (ucMemberId < 1)
                                    {
                                        result.AddError("当前用户未映射到用户中心");
                                    }
                                    else
                                    {

                                        var cartWithSubTotal = cartWithWallets.Select(s => new { s.CartItem, s.Wallets, SubTotal = _priceCalculationService.GetSubTotal(s.CartItem) });
                                        var total = cartWithSubTotal.Select(s => s.SubTotal).Sum();
                                        if (total != processPaymentRequest.OrderTotal)
                                        {
                                            result.AddError("暂不支持优惠扣减和附加运费");
                                        }
                                        else
                                        {
                                            WalletTemplate lastWallet = null;
                                            decimal maxTotalValue = 0;
                                            decimal totalvalue = 0;
                                            foreach (var item in cartWithSubTotal)
                                            {
                                                decimal maxValue = 0;
                                                decimal value = 0;
                                                lastWallet = item.Wallets.SingleOrDefault();
                                                if (lastWallet != null)
                                                {
                                                    if (lastWallet.CalcType == (byte)WalletCalcType.Percent)
                                                    {
                                                        //TODO 由于只支持单个钱包所以最小最大支付值为100%
                                                        if (lastWallet.Value != 100)
                                                        {
                                                            result.AddError("当使用百分比计算时,支付值需设置为100%");
                                                            break;
                                                        }
                                                        if (lastWallet.MaxValue < 0 || lastWallet.MaxValue > 100)
                                                        {
                                                            result.AddError("当使用百分比计算时,最大支付值需设置为0到100%");
                                                            break;
                                                        }
                                                        maxValue = item.SubTotal * (lastWallet.MaxValue / 100);
                                                        value = item.SubTotal * (lastWallet.Value / 100);
                                                    }
                                                    else if (lastWallet.CalcType == (byte)WalletCalcType.Absolute)
                                                    {
                                                        if (lastWallet.Value != item.SubTotal)
                                                        {
                                                            result.AddError("当使用绝对值计算时,支付值需设置为产品价格");
                                                            break;
                                                        }
                                                        if (lastWallet.MaxValue < 0 || lastWallet.MaxValue > lastWallet.Value)
                                                        {
                                                            result.AddError("当使用绝对值计算时,支付值需设置为0到产品价格");
                                                            break;
                                                        }
                                                        maxValue = lastWallet.MaxValue;
                                                        value = lastWallet.Value;
                                                    }
                                                    else
                                                    {
                                                        result.AddError("未被支持的钱包计算方式");
                                                        break;
                                                    }
                                                    maxTotalValue += maxValue;
                                                    totalvalue += value;
                                                }
                                                else
                                                {
                                                    result.AddError("商品未设置钱包");
                                                    break;
                                                }

                                            }
                                            if (result.Errors.Count < 1)
                                            {
                                                var sdk = _paySdkHelper.Get();
                                                var grpcWallet = sdk.GetWallet(ucMemberId, lastWallet.WalletId).Result;
                                                var haveWallet = false;
                                                if (grpcWallet.Success)
                                                {
                                                    haveWallet = true;
                                                }
                                                else
                                                {
                                                    if (grpcWallet.Code.Equals("8007"))
                                                    {
                                                        var grpcCreateResult = sdk.CreateWalletAsync(ucMemberId, lastWallet.WalletId, lastWallet.Name, lastWallet.IconUrl).Result;
                                                        haveWallet = grpcCreateResult.Success;
                                                        if (!haveWallet)
                                                        {
                                                            result.AddError(grpcCreateResult.Message);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        result.AddError(grpcWallet.Message);
                                                    }
                                                }
                                                if (haveWallet)
                                                {

                                                    //#if DEBUG
                                                    //                                                    totalvalue = totalvalue / 1000;
                                                    //                                                    maxTotalValue = maxTotalValue / 1000;
                                                    //#endif

                                                    var payWallet = new List<PayWallet>{
                                                        new PayWallet()
                                                        {
                                                            Amount = Convert.ToInt32(totalvalue * 100),
                                                            MaxAmount = Convert.ToInt32(maxTotalValue * 100),
                                                            AutoDeposit = true,
                                                            Type = cartWithSubTotal.First().Wallets.First().WalletId    }   };



                                                    var payResult = sdk.AppPayAsync(new AppPayRequest()
                                                    {
                                                        Body = $"支付订单({processPaymentRequest.OrderGuid})",
                                                        MemberId = ucMemberId,
                                                        OutTradeNo = processPaymentRequest.OrderGuid.ToString(),
                                                        Subject = "购买商品",
                                                        TotalAmount = Convert.ToInt32(totalvalue * 100),
                                                        PayWallets = payWallet
                                                    }).Result;
                                                    if (payResult.Success)
                                                    {
                                                        result.AuthorizationTransactionId = payResult.OrderId.ToString();
                                                        result.AuthorizationTransactionResult = JsonConvert.SerializeObject(payResult.Wallets);
                                                    }
                                                    else
                                                    {
                                                        result.AddError(payResult.Message);
                                                    }
                                                }

                                            }
                                        }
                                    }

                                }
                            }
                        }
                    }
                    else
                    {
                        result.AddError("订单Id不匹配");
                    }


                }
                else
                {
                    result.AddError("订单支付信息类型错误");
                }
            }
            return result;
        }


        /// <summary>
        /// 签约支付
        /// </summary>
        /// <param name="processPaymentRequest"></param>
        /// <returns></returns>
        public ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 退款
        /// </summary>
        /// <param name="refundPaymentRequest"></param>
        /// <returns></returns>
        public RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public IList<string> ValidatePaymentForm(IFormCollection form)
        {
            List<string> errors = new List<string>();
            if (form.TryGetValue("cartIds", out StringValues cartValues))
            {
                if (cartValues.Count > 0)
                {
                    var cartIdList = form["cartIds"].First().Split(",").Select(s => int.Parse(s)).ToList();

                    if (cartIdList.Count() < 1)
                    {
                        errors.Add("购物车为空");
                    }
                }
                else
                {
                    errors.Add("购物车为空");
                }
            }
            else
            {
                errors.Add("购物车为空");
            }
            return errors;
        }

        public VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public override void Install()
        {
            base.Install();
        }


    }
}
